/******************************************************
*  Copyright(c) pages.ilovezxl.top
*  FileName :cfg.c
*  Author : rivulet.dave
*  Description : 参数配置模块
*  Data : 2020-07-21
******************************************************/

/*********************************************************************
 * INCLUDES
 */

#include "stdrope.h"

#include "sallib.h"
#include "salagent.h"

#include "cli.h"
#include "log.h"
#include "threadasync.h"
#include "mem.h"
#include "cfg.h"

#if (SAL_CFG_INI == _ENABLE)
#include "cfg_ini.h"
#endif

/*********************************************************************
 *  EXTERNAL VARIABLES
 */

/*********************************************************************
 * MACROS
 */

#define CFG_LOG(level, ...) LOG_Output(s_stCfgInfo.pName, LOG_LEVEL_RAW, 0, __FILENAME__, __LINE__, ## __VA_ARGS__)

/*********************************************************************
 * TYPES
 */

typedef struct _cfg_obj
{
    const char *pFile;
    uint32_t uiFlashAddr;
    osMutexId_t iLock;
    int32_t iFormat;
    int32_t iMode;
} CFG_OBJ_S;

typedef struct _cfg_block
{
    CFG_OBJ_S *pstCfgObj;
    uint32_t uiOffset;
    uint32_t uiSize;
} CFG_BLOCK_S;

/*********************************************************************
 * FUNCTIONS DECLARE
 */

static void CFG_CliCallback(char *pArg);

/*********************************************************************
 *  VARIABLES
 */

static MOD_INFO_S  s_stCfgInfo = { .uiModID = OS_CFG, .pName = TOSTR(OS_CFG)};
static CLI_INFO_S s_astCfgCliTbl[] =
{
    { "cfg", "configuration cmd.", CFG_CliCallback },
};

/*********************************************************************
 * FUNCTIONS
 */

/**
 *   @Description: 模块安装
 *   @param : NA
 *   @return: _OK/_ERR
 */
int32_t CFG_Install(void)
{
    CLI_Register(s_astCfgCliTbl, _ARRAY_SIZE(s_astCfgCliTbl));
    return _OK;
}

/**
 *   @Description: 模块卸载
 *   @param : NA
 *   @return: _OK/_ERR
 */
int32_t CFG_Uninstall(void)
{
    return _OK;
}

/**
 *   @Description: 创建参数配置存储object
 *   @param : uiAddr - flash地址，uiAddr不为0则表示使用Flash存储
 *   @param : pFile - 文件名，uiAddr为0时有效
 *   @param : iFormat - 存储格式_cfg_storage_format
 *   @return: cfgObjId_t
 */
cfgObjId_t CFG_ObjectNew(uint32_t uiAddr, const char *pFile, int32_t iFormat)
{
    CFG_OBJ_S *pstCfgObj = NULL;

    if (CFG_FMT_INI != iFormat && CFG_FMT_BIN != iFormat)
    {
        CFG_LOG(LOG_LEVEL_ERROR, "config obj format error.\n");
        return NULL;
    }

    pstCfgObj = (CFG_OBJ_S *)osMemAlloc(sizeof(CFG_OBJ_S));
    if (NULL == pstCfgObj)
    {
        CFG_LOG(LOG_LEVEL_ERROR, "config object create failed.\n");
        return NULL;
    }

    pstCfgObj->iLock = osMutexNew(NULL);
    if (NULL == pstCfgObj->iLock)
    {
        osMemFree((void **)&pstCfgObj);
        CFG_LOG(LOG_LEVEL_ERROR, "config object lock new failed.\n");
        return NULL;
    }

    if (0 == uiAddr)
    {
        pstCfgObj->iMode = CFG_MODE_FILE;
    }
    else
    {
        pstCfgObj->iMode = CFG_MODE_FLASH;
    }
    pstCfgObj->uiFlashAddr = uiAddr;
    pstCfgObj->pFile = pFile;
    pstCfgObj->iFormat = iFormat;
    return (cfgObjId_t)pstCfgObj;
}

/**
 *   @Description: 删除参数配置存储object
 *   @param : pCfgObj - CFG_ObjectNew函数返回的存储Object
 *   @return: _OK/_ERR
 */
int32_t CFG_ObjectDelete(cfgObjId_t pCfgObj)
{
    CFG_OBJ_S *pstCfgObj = (CFG_OBJ_S *)pCfgObj;

    if (!pstCfgObj)
    {
        return _ERR;
    }

    osMutexDelete(pstCfgObj->iLock);
    osMemFree((void **)&pstCfgObj);
    return _OK;
}

static void CFG_CliTest(char *pArg)
{
    char *pNextArg;
    cfgObjId_t pstCfgObj;
    char acKey[CLI_CMD_NAME_MAX_LEN];
    char acValue[CLI_CMD_NAME_MAX_LEN];

    pNextArg = CLI_KeyNext(pArg, acKey);
    if (0 == strcmp(acKey, "iniw"))
    {
        pNextArg = CLI_KeyNext(pNextArg, acKey);
        pNextArg = CLI_KeyNext(pNextArg, acValue);
        pstCfgObj = CFG_ObjectNew(0, "tools/ini/example.ini", CFG_FMT_INI);
        if (!pstCfgObj)
        {
            CLI_Output("ERR: cfg object new fail.\n");
        }
        else
        {
            if (_OK != CFG_IniWrite(pstCfgObj, "test", acKey, acValue))
            {
                CLI_Output("ERR: cfg write fail.\n");
            }
            else
            {
                CLI_Output("SUCC: cfg write ok!\n");
            }
            CFG_ObjectDelete(pstCfgObj);
        }
    }
    else if (0 == strcmp(acKey, "inir"))
    {
        pNextArg = CLI_KeyNext(pNextArg, acKey);
        pstCfgObj = CFG_ObjectNew(0, "tools/ini/example.ini", CFG_FMT_INI);
        if (!pstCfgObj)
        {
            CLI_Output("ERR: cfg object new fail.\n");
        }
        else
        {
            if (_OK != CFG_IniRead(pstCfgObj, "test", acKey, acValue, sizeof(acValue)))
            {
                CLI_Output("ERR: cfg read fail.\n");
            }
            else
            {
                CLI_Output("SUCC: cfg read ok:%s\n", acValue);
            }
            CFG_ObjectDelete(pstCfgObj);
        }
    }
    else
    {
        CLI_Output("Usage: test [iniw | inir] ...\n");
    }
}

static void CFG_CliCallback(char *pArg)
{
    char *pNextArg;
    char acCliKey[CLI_CMD_NAME_MAX_LEN] = {0};

    pNextArg = CLI_KeyNext(pArg, acCliKey);
    if (0 == strcmp(acCliKey, "test"))
    {
        CFG_CliTest(pNextArg);
    }
    else
    {
        CLI_Output("Usage: cfg test ...\n");
    }
    
    CLI_Exit();
}

#if (SAL_CFG_INI == _ENABLE)

/**
 *   @Description: 读取ini格式参数配置
 *   @param : pCfgObj - CFG_ObjectNew函数返回的存储Object
 *   @param : pSection - ini文件section
 *   @param : pKey - ini文件关键字
 *   @param : pValue - 读取的数据缓存
 *   @param : uiSize - 缓存大小
 *   @return: _OK/_ERR
 */
int32_t CFG_IniRead(cfgObjId_t pCfgObj, const char *pSection, const char *pKey, char *pValue, uint32_t uiSize)
{
    CFG_OBJ_S *pstCfgObj = (CFG_OBJ_S *)pCfgObj;

    if (!pstCfgObj)
    {
        return _ERR;
    }

    if (CFG_FMT_INI != pstCfgObj->iFormat)
    {
        CFG_LOG(LOG_LEVEL_ERROR, "config object fmt is not ini.\n");
        return _ERR;
    }

    if (CFG_MODE_FILE == pstCfgObj->iMode)
    {
        return INI_Read(pstCfgObj->pFile, pSection, pKey, pValue, uiSize);
    }
    
    if (CFG_MODE_FLASH == pstCfgObj->iMode)
    {
        return INI_ReadFlash(pstCfgObj->uiFlashAddr, pSection, pKey, pValue, uiSize);
    }

    return _ERR;
}

/**
 *   @Description: 写入ini格式参数配置
 *   @param : pCfgObj - CFG_ObjectNew函数返回的存储Object
 *   @param : pSection - ini文件section
 *   @param : pKey - ini文件关键字
 *   @param : pValue - 写入的数据
 *   @return: _OK/_ERR
 */
int32_t CFG_IniWrite(cfgObjId_t pCfgObj, const char *pSection, const char *pKey, const char *pValue)
{
    CFG_OBJ_S *pstCfgObj = (CFG_OBJ_S *)pCfgObj;

    if (!pstCfgObj)
    {
        return _ERR;
    }

    if (CFG_FMT_INI != pstCfgObj->iFormat)
    {
        CFG_LOG(LOG_LEVEL_ERROR, "config object fmt is not ini.\n");
        return _ERR;
    }

    if (CFG_MODE_FILE == pstCfgObj->iMode)
    {
        return INI_Write(pstCfgObj->pFile, pSection, pKey, pValue);
    }
    
    if (CFG_MODE_FLASH == pstCfgObj->iMode)
    {
        return INI_WriteFlash(pstCfgObj->uiFlashAddr, pSection, pKey, pValue);
    }

    return _ERR;
}

#endif //(SAL_CFG_INI == _ENABLE)

#if (SAL_CFG_BIN == _ENABLE)

/**
 *   @Description: 创建二进制存储Block，Block是Object下属单位
 *   @param : pCfgObj - CFG_ObjectNew函数返回的存储Object
 *   @param : uiAddr - Flash初始地址
 *   @param : uiSize - 存储空间大小
 *   @return: cfgBlockId_t
 */
cfgBlockId_t CFG_BinBlockNew(cfgObjId_t pCfgObj, uint32_t uiAddr, uint32_t uiSize)
{
    return NULL;
}

/**
 *   @Description: 删除二进制存储Block，Block是Object下属单位
 *   @param : pCfgBlock - CFG_BinBlockNew函数返回值
 *   @return: _OK/_ERR
 */
int32_t CFG_BinBlockDelete(cfgBlockId_t pCfgBlock)
{
    return _OK;
}

/**
 *   @Description: 读取二进制存储Block数据
 *   @param : pCfgBlock - CFG_BinBlockNew函数返回值
 *   @param : pData - 读取的数据缓存
 *   @param : uiSize - 缓存大小
 *   @return: _OK/_ERR
 */
int32_t CFG_BinRead(cfgBlockId_t pCfgBlock, uint8_t *pData, uint32_t uiSize)
{
    return _OK;
}

/**
 *   @Description: 写入二进制存储Block数据
 *   @param : pCfgBlock - CFG_BinBlockNew函数返回值
 *   @param : pData - 写入的数据
 *   @param : uiSize - 写入的数据大小
 *   @return: _OK/_ERR
 */
int32_t CFG_BinWrite(cfgBlockId_t pCfgBlock, uint8_t *pData, uint32_t uiSize)
{
    return _OK;
}

#endif  //(SAL_CFG_BIN == _ENABLE)

/************************************** The End Of File **************************************/



